
package tableur;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;

import javax.swing.AbstractAction;
import javax.swing.ButtonGroup;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.filechooser.FileNameExtensionFilter;

import structure.DataCenter;
import structure.ListDataCenter;
import structure.MapDataCenter;
import structure.Structure;
import structure.TabDataCenter;
import structure.ArbreDataCenter;

/**
 * Panneau d'un tableur
 * 
 * @author Robert Aubé
 * @author David Bernard
 * @version 1.1 - 31 octobre 2008 (Robert Aubé)
 * @version 1.1 - 15 octobre 2010 (Jocelyn Goulet)
 * @version 1.2 - 06 novembre 2011 (David Bernard)
 * 
 * @since java 1.6
 */
public class Tableur extends JFrame
{
	private static final String TITRE = "Mon chiffrier";
	private static final String EXTENSION = "tlux";

	/**
	 * Définit le nombre de lignes du tableau.
	 */
	public static final int MAX_LIGNE = 900;

	/**
	 * Définit le nombre de colonne du tableau.
	 */
	public static final int MAX_COLONNE = 0x00FF;

	/**
	 * Définit le dossier de sauvegarde de base.
	 */
	public static final String DOSSIER_SAUVEGARDE = ".//data1";

	private TableManager table = null;

	private AbstractAction aboutAct = null;
	private AbstractAction ouvrirCmd = null;
	private AbstractAction saveCmd = null;
	private AbstractAction saveAsCmd = null;
	private AbstractAction closeCmd = null;
	private AbstractAction exitCmd = null;

	private File monFichier = null;
	private String nomStructure = null;
	private boolean dataModifie = false;

	/**
	 * Structure mémorisant les valeurs des cellules
	 */
	private DataCenter valCellules = null;

	/**
	 * Instancie un nouveau tableur.
	 * 
	 */
	public Tableur()
	{
		//Tableur.runTests();

		Tableur.prepareDossierSauvegarde();

		this.initJFrame();
		this.initTable();
		this.initActions();
		this.initMenuBar();

		this.buildDataCenter(Structure.Vector.name());
	}

	private void initJFrame()
	{
		this.addWindowListener(new LocalWindowAdapter());
		this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
		this.setExtendedState(JFrame.MAXIMIZED_BOTH);
		this.setLayout(new BorderLayout());
	}

	private void initTable()
	{
		// Ajouter les 2 tables au JScrollPane
		this.table = new TableManager();
		this.table.addTableListener(new EcouteurTable());
		this.add(this.table.getPane(), BorderLayout.CENTER);
	}

	private void initActions()
	{
		this.aboutAct = new AboutAction();
		this.ouvrirCmd = new OuvrirCmd();
		this.saveCmd = new SaveCmd();
		this.saveAsCmd = new SaveAsCmd();
		this.closeCmd = new CloseCmd();
		this.exitCmd = new ExitCmd();
	}

	private void buildDataCenter(String command)
	{
		DataCenter prototype = null;

		if (ListDataCenter.validerType(command))
		{
			prototype = new ListDataCenter(command);
		}
		else if (MapDataCenter.validerType(command))
		{
			prototype = new MapDataCenter(command);
		}
		else if (command.equalsIgnoreCase(Structure.Tableau.name()))
		{
			prototype = new TabDataCenter();
		}
		else if (command.equalsIgnoreCase(Structure.ArbreBinaire.name()))
		{
			prototype = new ArbreDataCenter();
		}

		if ((prototype != null) && this.confirmationFermeture())
		{
			this.valCellules = prototype;
			this.table.setDataCenter(prototype);
			this.nomStructure = command;
			this.monFichier = null;
			this.dataModifie = false;
			this.updateTitre();
		}
	}

	private void initMenuBar()
	{
		JMenuBar menuBar = new JMenuBar();
		JMenu menu = null;

		// Menu Fichier
		menu = new JMenu("Fichier");
		menu.add(this.ouvrirCmd);
		menu.add(this.saveCmd);
		menu.add(this.saveAsCmd);
		menu.add(this.closeCmd);
		menu.addSeparator();
		menu.add(this.exitCmd);
		menuBar.add(menu);

		// Menu "Structure de données"
		menu = new StructureMenu();
		menu.add(Structure.Vector.name());
		menu.add(Structure.ArrayList.name());
		menu.add(Structure.LinkedList.name());
		menu.addSeparator();
		menu.add(Structure.HashMap.name());
		menu.add(Structure.Hashtable.name());
		menu.add(Structure.TreeMap.name());
		menu.addSeparator();
		menu.add(Structure.Tableau.name());
		menu.add(Structure.ArbreBinaire.name());
		menu.getItem(0).setSelected(true);

		menuBar.add(menu);

		// Menu "?"
		menu = new JMenu("?");
		menu.add(this.aboutAct);
		menuBar.add(menu);

		this.setJMenuBar(menuBar);
	}

	private void quitter()
	{
		if (this.confirmationFermeture())
		{
			System.exit(0);
		}
	}

	private void updateTitre()
	{
		String titre = Tableur.TITRE;
		titre += " - " + this.nomStructure;

		if (this.monFichier != null)
		{
			titre += " - " + this.monFichier.getName();
		}

		if (this.dataModifie)
		{
			titre += " *";
		}

		this.setTitle(titre);
	}

	private void enregistre()
	{
		if (this.monFichier == null)
		{
			this.enregistrerSous();
		}
		else
		{
			this.valCellules.Enregistrer(this.monFichier.getAbsolutePath());
			this.dataModifie = false;
			this.updateTitre();
		}
	}

	private void enregistrerSous()
	{
		File file = this.choisirFichier(true);

		if (file != null)
		{
			this.valCellules.Enregistrer(file.getAbsolutePath());
			this.dataModifie = false;
			this.monFichier = file;
			this.updateTitre();
		}
	}

	private void fermer()
	{
		if (this.confirmationFermeture())
		{
			this.valCellules.removeAllData();
			this.monFichier = null;
			this.dataModifie = false;
			this.updateTitre();
		}
	}

	private void ouvrir()
	{
		File nomFichier = this.choisirFichier(false);

		if (nomFichier != null)
		{
			this.monFichier = nomFichier;
			this.valCellules.Ouvrir(nomFichier.getAbsolutePath());
			this.dataModifie = false;
			this.updateTitre();
		}
	}

	private File choisirFichier(boolean save)
	{
		String nomFichier = null;
		JFileChooser jfc = new JFileChooser(Tableur.DOSSIER_SAUVEGARDE);
		FileNameExtensionFilter filter = new FileNameExtensionFilter(
				"Tableur Limoulux *." + Tableur.EXTENSION, Tableur.EXTENSION);

		jfc.setFileFilter(filter);

		File fichier = null;
		int retour = 0;

		if (save)
		{
			retour = jfc.showSaveDialog(this);
		}
		else
		{
			retour = jfc.showOpenDialog(this);
		}

		if (retour == JFileChooser.APPROVE_OPTION)
		{
			fichier = jfc.getSelectedFile();

			if (save && !filter.accept(fichier))
			{
				nomFichier = fichier.getAbsolutePath();
				nomFichier += "." + Tableur.EXTENSION;
				fichier = new File(nomFichier);
			}
		}

		return fichier;
	}

	private boolean confirmationFermeture()
	{
		boolean confirme = false;
		int choix = 0;

		if (this.dataModifie)
		{
			choix = JOptionPane.showConfirmDialog(this,
					"Voulez-vous souvegarder?", "Confirmation",
					JOptionPane.YES_NO_CANCEL_OPTION);

			if (choix != JOptionPane.CANCEL_OPTION)
			{
				confirme = true;
				if (choix == JOptionPane.YES_OPTION)
				{
					this.enregistre();
				}
			}
		}
		else
		{
			confirme = true;
		}

		return confirme;
	}

	private class EcouteurTable implements TableListener
	{
		@Override
		public void dataModifie()
		{
			Tableur.this.dataModifie = true;
			Tableur.this.updateTitre();
		}
	}

	private class LocalWindowAdapter extends WindowAdapter
	{
		@Override
		public void windowClosing(WindowEvent e)
		{
			Tableur.this.quitter();
		}
	}

	private class StructureMenu extends JMenu
	{
		private ButtonGroup bGroup = null;

		private StructureMenu()
		{
			super("Structure de données");
			this.bGroup = new ButtonGroup();
		}

		@Override
		public JMenuItem add(String command)
		{
			AbstractAction act = new StructureCommand(command);
			JRadioButtonMenuItem rb = new JRadioButtonMenuItem(act);
			this.bGroup.add(rb);
			return this.add(rb);
		}
	}

	private class StructureCommand extends AbstractAction
	{
		private StructureCommand(String command)
		{
			super(command);
		}

		@Override
		public void actionPerformed(ActionEvent e)
		{
			Tableur.this.buildDataCenter(e.getActionCommand());
		}
	}

	private class AboutAction extends AbstractAction
	{
		private AboutAction()
		{
			super("About");
		}

		@Override
		public void actionPerformed(ActionEvent arg0)
		{
			String msg = "";

			msg += "Tableur\n";
			msg += Tableur.this.valCellules;
			JOptionPane.showMessageDialog(Tableur.this, msg);
		}

	}

	private class OuvrirCmd extends AbstractAction
	{
		private OuvrirCmd()
		{
			super("Ouvrir...");
		}

		@Override
		public void actionPerformed(ActionEvent e)
		{
			Tableur.this.ouvrir();
		}
	}

	private class SaveCmd extends AbstractAction
	{
		private SaveCmd()
		{
			super("Enregistrer");
		}

		@Override
		public void actionPerformed(ActionEvent e)
		{
			Tableur.this.enregistre();
		}

	}

	private class SaveAsCmd extends AbstractAction
	{
		private SaveAsCmd()
		{
			super("Enregistrer sous...");
		}

		@Override
		public void actionPerformed(ActionEvent e)
		{
			Tableur.this.enregistrerSous();
		}
	}

	private class CloseCmd extends AbstractAction
	{
		private CloseCmd()
		{
			super("Fermer");
		}

		@Override
		public void actionPerformed(ActionEvent e)
		{
			Tableur.this.fermer();
		}
	}

	private class ExitCmd extends AbstractAction
	{
		private ExitCmd()
		{
			super("Quitter");
		}

		@Override
		public void actionPerformed(ActionEvent e)
		{
			Tableur.this.quitter();
		}
	}

	private static void prepareDossierSauvegarde()
	{
		File dateRep = new File(Tableur.DOSSIER_SAUVEGARDE);
		if (!dateRep.exists())
		{
			dateRep.mkdir();
			// System.out.println("creation de " + dateRep.getAbsolutePath());
		}
		else
		{
			// System.out.println(dateRep.getAbsolutePath() + " existe deja");
		}
	}

	private static void runTests()
	{
		new Testeur();

	}

	/**
	 * Point d'entré du programme.
	 * 
	 * @param args Non-Implémenté
	 */
	public static void main(String[] args)
	{
		Tableur tableur = new Tableur();

		tableur.setVisible(true);
	}
}
